--
-- Author:      name
-- DateTime:    2022-08-21 15:57:48
-- Description: 游戏主逻辑

local FSM = require("fsm")
local cjson = require("cjson")

local table_insert = table.insert
local table_remove = table.remove
local math_floor = math.floor


--------------------------------class---------------------------------
local DeskBase = require("games.common.desk")
local Desk = DeskBase:extend("Desk")

function Desk:ctor()
	--注意写上这个是为了让更新基类时，对象能同步上变更，但要注意同名函数可能会产生覆盖
	self.super:setModuleName("games.common.desk")
	Desk.super.ctor(self)
	self:register()
end

function Desk:register()
	if self.test then
		self:test()
	end
end

----------------------------------------------------------------------------------------------
---------开始游戏
---------------------------------------------------------------------------------------------- 
function Desk:init()
	print("___初始化游戏桌子___", g.tid)
	self.sb = nil
	self.bb = nil --大盲注
	self.closed = false --桌子关闭
	self.cur_oper = nil --当前操作者
	self.next_oper = nil --下一个操作者
	self.banker = nil --当前庄家
	self.banker_seat_id = nil --庄位置
	self.sb_seat_id = nil --庄位置
	self.bb_seat_id = nil --庄位置
	self.co_seat_id = nil --枪口位置
	self.cur_oper_seat_id = nil --当前操作者位置
	self.total_bet = 0 --当前局总下注
	self.cur_bet = 0 --当前下注额度
	self.stage_bet = 0 --当前轮下注额度, 最小跟注
	self.min_raise_bet = 0 --最小加注值
	self.stage_bet_count = 0 --本局加注次数
	self.follow_bet = 0 --当前需要最小跟注
	self.last_raise_bet = 0 --本轮最后一个加注的额度

	self.common_cards = {} --公牌
	self.pots = {} --主池和边池
	self.pot_seats = {} --每个池对应的玩家位置{{1,2,4}, {}}
	self.seat_bet = {} --各位置下注金额
	self.cur_stage = nil --当前状态
	self.start_play_limit = 2 --开始游戏需要的人数
	self.bb_user = nil --大盲玩家
	self.sb_user = nil --小盲玩家
	self.allined = false --所有人allin
	self.user_show_cards = {} --要开牌的玩家
	self.pre_bet = 0 --当前前注

	self.oper_timer = new("base.timer")
	self.oper_timer_id = 0 --定时器id
	self.check_desk = false
	self.jackpot = 0 --奖池
	self.is_calc_over = true --是结算完毕
	self.use_skill = false --使用必杀技能
	self.robot_chip_pool = 0 --桌子累计输赢金币值
	self.need_uid = nil --给必杀的玩家

	--配置信息
	--状态名
	self.s_stage_start = "start"
	self.s_stage_preflop   = "preflop"
	self.s_stage_flop      = "flop"
	self.s_stage_turn      = "turn"
	self.s_stage_river     = "river"
	self.s_stage_over 	   = "over"
	self.s_stage_rest 	   = "rest"
	--状态时间
	self.stateTime = {
		start = 1,		--开始
		oper = 15,		--操作时间
		over = 5, 		--结束游戏
		rest = 1,		--等待
	}
	--游戏状态
	self.state_num ={
		[self.s_stage_start] = 1,
		[self.s_stage_preflop] = 2,
		[self.s_stage_flop] = 3,
		[self.s_stage_turn] = 4,
		[self.s_stage_river] = 5,
		[self.s_stage_over] = 6,
		[self.s_stage_rest] = 7,
	}
	--休息，开始玩家操作，抢庄, 下注，发牌，结算
	--state1 --eventName --state2 --callback
	self.stateTable = {
		{"rest", 	"to_start", 	"start", 	function() self:stStart() end }, --state start
		{"start", 	"to_preflop", 	"preflop", 	function() self:stPreflop() end },
		{"preflop", "to_flop",		"flop", 	function() self:stFlop() end },
		{"flop", 	"to_turn",		"turn", 	function() self:stTurn() end },
		{"turn", 	"to_river",		"river", 	function() self:stRiver() end },
		{"*", 		"to_over",		"over", 	function() self:stOver() end },
		{"*", 		"to_rest",		"rest", 	function() self:stReset() end },
	}
	self.fsm = FSM.new(self.stateTable)
	--启动状态机
	self.fsm:set("over")
	self.fsm:fire("to_rest")

	g.loop(100, function()
		self:update()
	end)

	self:test()
end

--定时检测桌子
function Desk:update()
	local cd_time = self.oper_timer:getCD(self.oper_timer_id)
	if cd_time and cd_time>0 then
		print("#########"..g.tid, self:getStage(), cd_time)
	end

	if not self.check_desk then
		self.check_desk = true
		local time_id = self.oper_timer_id
		g.timeout(20, function()
			if self:getStage() ~= self.s_stage_rest and self.oper_timer:getCurrId() == time_id then
			--if g.user_mgr:getSeatUsersNum() > 0 then
				--卡住了
				g.log:deskErr("the desk state is err, auto close it! ", g.user_mgr:getUsersNum())
				g.sendGames("close_game", g.tid)
				--return
			end
			self.check_desk = false
		end)

	end
	--如果只有一个人在桌子里，超过一定时间应该踢出这个人

end

--状态时间表
function Desk:getStateTime()
	return self.stateTime
end

--重置数据
function Desk:reset()
	self.cur_oper = nil
	self.total_bet = 0 --当前局总下注
	self.cur_bet = 0
	self.cur_stage = nil --当前状态
	self.stage_bet = 0
	self.min_raise_bet = 0
	self.common_cards = {}
	self.seat_bet = {}
	self.seat_count = g.room_cfg.seat_count
	self.allined = false --所有人allin
	self.user_show_cards = {}
	self.pre_bet = 0 --当前前注
	self.follow_bet = 0 --当前需要最小跟注
	self.last_raise_bet = 0 --本轮最后一个加注的额度
	self.stage_bet_count = 0 --本局加注次数

	self.stage_logs = {} --每个状态的下注情况
	self.round_start_time = 0 --每局开始时间
	self.total_fee = 0 --每局的税

	local users = g.user_mgr:getUsers()
	for _, user  in pairs(users) do
		if user:getChipDelay() > 0 then
			--通知所有玩家
			local data = {
				tid = g.tid,
				mid = user:getUid(),
				seat_chips = user:getChip()+user:getChipDelay(),
				seatid = user:getSeatId(),
			}
			self:sendUsers("TS_2C_buyinchipsBc", data)
		end
		user:chipInit(user.s_status_init)
		if user:isRobot() then
			if not g.const.switch.bot_normal then
				--关闭机器人
				self:kickUser(user)
			end
		end

	end
	self.pots = {} --主池和边池
	self.pot_seats = {} --每个池对应的玩家位置
	for i=1, self.seat_count do
		table_insert(self.pots, 0)
		table_insert(self.pot_seats, {})
	end
	self.players = {} --参与游戏的玩家
end

--下一个操作者
function Desk:findNextOper()
	--应该有先有庄，从庄的下一位开始
	local seat_id = self.cur_oper_seat_id or self.banker_seat_id
	if not self.cur_oper_seat_id and self:getStage() == self.s_stage_preflop then
		--print("####1#findNextOper#####")
		--牌前是大盲下一位开始下注
		seat_id = self.bb_user:getSeatId()
	end
	--print("####2#findNextOper##seat_id###", seat_id)
	local count = seat_id + self.seat_count
	local tmp_seat_id = 0
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			--下注状态
			local action = user:getAction()
			if action == user.s_bet_init or action == user.s_bet_pre or
					(user:getStageBet() < self.stage_bet and action ~= user.s_bet_fold and action ~= user.s_bet_allin) or
					(user:getStageBet() == self.stage_bet and action == user.s_bet_bb) then
				--print("####3#findNextOper##seat_id###", tmp_seat_id, user:getUid())
				return user
			end
		end
	end
	return
end

--取池子
function Desk:getPot()
	local pots = {}
	if self:getStage() == self.s_stage_rest then
		return pots
	end
	if self.pots[1] == 0 then
		--没有分池的情况
		--print("##########pushPot1 ", self.total_bet)
		if self:getStage() == self.s_stage_preflop then
			return pots
		end
		table_insert(pots, {pot=self.total_bet})
	else
		--print("##########pushPot2 ", self.pots[1])
		for _, v in pairs(self.pots) do
			local pot = {pot = v}
			table_insert(pots, pot)
		end
	end
	return pots
end

-- 返回公牌
function Desk:getCommonCards()
	local cards = {}
	for _, v in pairs(self.common_cards) do
		table.insert(cards, {card=v})
	end
	return cards
end



-------------------------------------------------------------------------------
-- 推送消息
-------------------------------------------------------------------------------
-- 下注计算
function Desk:checkBet(seat_id, chips)
	local flag = false
	local user = g.user_mgr:getSeatUser(seat_id)
	if not user then return flag end
	local uid = user:getUid()
	--如果只剩下一个人在玩，下注都是无效的
	if g.user_mgr:getPlayingUserNum() <= 1 then
		g.log:deskInfo(uid, "checkBet player user num <= 1")
		return false
	end
	-- 弃牌
	if chips < 0 then
		flag = true
		return flag
	end
	-- allin
	local chip = user:getChip()
	if chip == chips then
		flag = true
		return flag
	end
	if chip < chips then -- 不够下注
		g.log:deskWarn(uid, "checkBet chip not enough")
		return flag
	end
	-- check
	local stage_bet = user:getStageBet() --当前轮已下注
	if chips == 0 then
		if stage_bet ~= self.stage_bet then -- 看牌错误
			g.log:deskWarn(uid, "checkBet check stage_bet ~= self.stage_bet", stage_bet, self.stage_bet)
			return false
		end
		flag = true
		return flag
	end

	stage_bet = chips + stage_bet
	-- 跟注
	if stage_bet == self.stage_bet then
		flag = true
		return flag
	end
	-- 下(加)注 必须大于 大盲
	if stage_bet < self.bb then
		g.log:deskWarn(uid, "checkBet stage_bet < self.bb", seat_id, chips, stage_bet, self.bb)
		return flag
	end

	-- 等于跟注值  或者 >= 最小加注值 都能下
	-- 翻牌前 跟注值 必须 等于 大盲
	if self.stage_bet > 0 and self.stage_bet < self.bb and self:getStage() == self.s_stage_preflop then
		self.stage_bet = self.bb
		--self.min_raise_bet = self.bb
	end
	if stage_bet == self.stage_bet or stage_bet >= self.min_raise_bet then
		flag = true
		return flag
	end-- checkBet faild 4 120800 341600 341614 391600 500 false false
	g.log:deskWarn(uid, "checkBet faild", seat_id, chip, chips, stage_bet, self.stage_bet, self.min_raise_bet, self.bb, stage_bet == self.stage_bet, stage_bet >= self.min_raise_bet)
	return flag
end

--下注
function Desk:betting(seat_id, chips, act)
	--print("######betting######", seat_id, chips, act)
	local flag = false
	if not act and self:checkBet(seat_id, chips) == false then
		g.log:deskInfo(0, "betting checkBet false: ", seat_id, chips, act)
		return false
	end
	local user = g.user_mgr:getSeatUser(seat_id)
	if not user then return flag end
	local user_chip = user:getChip()
	local action = 0
	if chips < 0 then
		--弃牌
		user:setStatus(user.s_status_giveup)
		action = user.s_bet_fold
		local folds = {
			[self.s_stage_preflop] = 1,
			[self.s_stage_flop] = 2,
			[self.s_stage_turn] = 3,
			[self.s_stage_river] = 4,
		}
		local num = folds[self.cur_stage] or 1
		user:setFold(num)
	elseif chips == 0 then
		--check
		action = user.s_bet_check
	else
		local u_stage_bet =  user:getStageBet() + chips
		if u_stage_bet <= self.stage_bet then
			--跟注
			action = user.s_bet_call_follow
		else
			--加注
			action = user.s_bet_raise
			if self.stage_bet_count == 0 then
				action = user.s_bet_call_first
			end
			self.stage_bet_count = self.stage_bet_count + 1
			self.last_raise_bet = u_stage_bet - self.stage_bet --本轮最后一个加注的额度
			--每一轮的加注次数
			user:addStageRaiseNum()
		end
		if u_stage_bet >= self.min_raise_bet then
			--最小加注值
			self.min_raise_bet = u_stage_bet * 2 - self.stage_bet
		end
		user:subChip(chips)
		if u_stage_bet > self.stage_bet then
			self.stage_bet = u_stage_bet
		end
	end
	if act then
		action = act
	end
	user:setAction(action)
	if chips > 0 and user:getChip() == 0 then
		user:setAction(user.s_bet_allin)
	end
	if chips > user_chip then
		chips = user_chip
	end
	if chips >= 0 then
		self.total_bet = self.total_bet + chips
		local u_stage_bet =  user:getStageBet() + chips
		user:setStageBet(u_stage_bet)
		user:addSeatBet(chips)
		user:addTotalBet(chips)
		self.seat_bet[seat_id] = (self.seat_bet[seat_id] or 0) + chips
	end
	user:setCurBet(chips)
	self:addBetLogs(user)
	self:pushBet(chips, user)


	g.log:deskDebug(uid, string.format("betting sid:%s, uchips:%s, chips:%s, act:%s,	u_stage_bet=%s, u_host_count=%s, r_stage_bet=%s, r_min_raise_bet=%s ",
			seat_id, user:getChip(), chips, user.s_bet_str[action], user:getStageBet(), user:getNoOperRound(), self.stage_bet, self.min_raise_bet))

	return chips

end

--下一个庄
function Desk:setBanker()
	self.banker_seat_id = self.banker_seat_id or 0
	local seat_id = self.banker_seat_id
	local count = self.banker_seat_id + self.seat_count
	local tmp_seat_id = 0
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			if self.old_player_num > 2 and self.sb_seat_id then
				self.banker_seat_id = self.sb_seat_id
				break
			end
			self.banker = user
			self.banker_seat_id = tmp_seat_id
			break
		end
	end

	--应该有先有庄，从庄的下一位是大盲，小盲
	local seat_id = self.banker_seat_id
	local count = seat_id + self.seat_count
	local tmp_seat_id = 0
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			self.sb_user = user
			self.sb_seat_id = tmp_seat_id
			break
		end
	end
	seat_id = self.sb_user:getSeatId()
	count = seat_id + self.seat_count
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			self.bb_user = user
			self.bb_seat_id = tmp_seat_id
			break
		end
	end

	seat_id = self.bb_user:getSeatId()
	count = seat_id + self.seat_count
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			--枪口位
			self.co_user = user
			self.co_seat_id = tmp_seat_id
			break
		end
	end
end

--改变状态
function Desk:changeStage(state)
	if not state then
		return
	end
	self.oper_timer:deltimer(self.oper_timer_id)
	g.fork(function()
		self:calcPots()
		self.cur_stage = state
		self.cur_oper = nil
		self.cur_oper_seat_id = nil
		self.stage_bet = 0 --当前轮下注额度
		self.min_raise_bet = self.bb
		local users = self:getPlayers()
		for _, user in pairs(users) do
			if user:getAction() ~= user.s_bet_allin then
				user:setAction(user.s_bet_init)
			end
			user:setStageBet(0)
		end
		g.log:deskDebug(0, "changeStage: ", state)
		self.fsm:fire("to_"..state)
		local state_num = self:getStageNum()
		if state_num > self.state_num[self.s_stage_start] and state_num < self.state_num[self.s_stage_rest] then
			self:addStageLogs()
		end
	end)
end

function Desk:nextStage(sleep_time)
	if sleep_time then
		g.sleep(sleep_time)
	end
	if self.cur_stage == self.s_stage_over or self.cur_stage == self.s_stage_rest then
		--这2个状态不能在这里切换
		return
	end
	local state = nil
	if not self.cur_stage then
		state = self.s_stage_start
	else
		local state_num = self.state_num[self.cur_stage]
		state_num = (state_num + 1) % 7
		local state_info = self.stateTable[state_num]
		if not state_info or not state_info[3] then
			g.log:deskErr(0, "nextStage ", self.cur_stage, state_num, self.stateTable)
			return
		end
		state = state_info[3]
	end
	self:changeStage(state)
end

function Desk:test()
	--local hand_cards = {0x22, 0x12}
	--local common_cards = {}
	--local rank = g.rule:evaluate(hand_cards, common_cards) --牌型
	--local kind = g.rule:getKind(rank)
	--g.log:warn("texas test rank:", rank)
	--g.log:warn("texas test kind:", kind)

	--local kind = 8
	--local hand_cards = {13, 28}
	--local common_cards = {4, 29, 61, 53, 45}
	--local best_cards = g.rule:getBestCards(kind, hand_cards, common_cards)
	--g.log:debug("best_cards:", best_cards)




end

-------------------------------------------------------------------------------
-- 状态
-------------------------------------------------------------------------------

--开始
function Desk:stStart()
	self:createRoundId()
	g.log:deskDebug(0, "onStart")
	self.sb = math_floor(g.room_cfg.small_blind)
	self.bb = math_floor(g.room_cfg.big_blind) --大盲注
	self.round_start_time = g.time()
	self.round_num = self.round_num + 1
	self.old_player_num = self:getOldPlayerNum() --上局在玩的人数
	g.rule:shuffle() --洗牌
	self.user_show_cards = {} --清掉要亮的牌
	self.final_cards = g.rule:getCommonCards(5)
	--设置玩家状态
	local users = g.user_mgr:getSeatUsers()
	for sid, user in pairs(users) do
		local can_in = true
		if self.old_player_num > 2 then
			--大小盲位之间的人不能入局
			if self.sb_seat_id < self.bb_seat_id then
				if sid > self.sb_seat_id and sid < self.bb_seat_id then
					can_in = false
				end
			else
				if sid > self.sb_seat_id or sid < self.bb_seat_id then
					can_in = false
				end
			end
		end
		if can_in then
			user:setStatus(user.s_status_gaming)
			user:addRound()
			--参与过这一局的都记录下
			self:addPlayer(user)
		end
	end
	self:checkSkill()
	self:sendAddRound()
	self:setBanker() --确定庄大小盲注位置
	--给玩家发广播消息
	self:pushStart()
	local callback = function ()
		self:changeStage(self.s_stage_preflop)
	end
	self.oper_timer_id = self.oper_timer:timeout(self.stateTime.start, callback)

end

--玩家操作
function Desk:playerOper(stage)
	g.log:deskDebug(0, "playerOper", stage)
	--当可操作人数少于2时直接跳过(2个人玩有1个弃牌
	local oper_count = 0
	local playing_num = g.user_mgr:getPlayingUserNum()
	local users = g.user_mgr:getSeatUsers()
	for _, user in pairs(users) do
		if user:isGaming() and user:getAction() ~= user.s_bet_allin then
			oper_count = oper_count + 1
		end
	end
	if oper_count == 1 then
		print("##########playerOper#####gaming player = 1")
		if playing_num == 1 then
			--都弃牌了
			self:changeStage(self.s_stage_over)
			return true
		elseif stage and stage ~= self.s_stage_preflop then
			--有人allin，直接跳到后续状态
			self:nextStage(100)
			return true
		end
	end
	--获取当前操作的玩家，等待其操作
	local next_oper = self:findNextOper()
	--没有下个操作者，进入下一轮
	if not next_oper then
		if playing_num >= self.start_play_limit then
			if stage then
				g.sleep(100) --停秒
			end
			self:nextStage()
			return true
		else
			self:changeStage(self.s_stage_over)
		end
		return
	end
	if oper_count == 1 and playing_num == 2 then
		--只有2个玩家时，上一个玩家allin 金额<=我下注金额，我不用再操作
		--如果2个人玩，大盲位不够交大盲， 小盲位还是要操作一下，因为self.stage_bet 至少是大盲 (self.stage_bet >= self.total_bet
		print("#####playerOper###oper_count1#######", self.stage_bet, next_oper:getStageBet(), next_oper:getUid(), next_oper:getSeatId())
		local follow_bet = self.stage_bet - next_oper:getStageBet()
		if follow_bet == 0 or self.stage_bet >= self.total_bet then
			--不需要操作
			self:nextStage()
			local sleep_time = 100
			if stage == self.s_stage_preflop then --大盲位不够交大盲时
				sleep_time = 200
			end
			g.sleep(sleep_time) --停1秒
			return true
		end
	end
	if self.cur_oper and next_oper:isSame(self.cur_oper) then
		g.log:deskInfo(0, "playerOper oper is same one:", self.cur_oper_seat_id)
		local follow_bet = self.stage_bet - self.cur_oper:getStageBet()
		if follow_bet == 0 then
			--不可能是同一个人操作2次
			self:nextStage()
			return true
		end
	end
	self.cur_oper = next_oper
	self.cur_oper_seat_id = self.cur_oper:getSeatId()
	self:pushNextOper()

	--设置个超时，如果不操作就自动操作弃牌
	local function fun()
		if not self.cur_oper then return end
		self.cur_oper:addNoOperNum()

		--离线状态检查
		self.cur_oper:checkLeave()

		--过牌或者弃
		local can_bet = false
		if self.cur_oper:getStageBet() == self.stage_bet then
			can_bet = self:betting(self.cur_oper_seat_id, 0)
		end
		if not can_bet then
			--弃牌
			self:betting(self.cur_oper_seat_id, -1)
		end
		self:playerOper()
	end
	local oper_time = self.stateTime.oper
	if self.cur_oper:getAutoPlay() == 1 then
		oper_time = 1.5
	end
	--操作定时
	self.oper_timer_id = self.oper_timer:timeout(oper_time, fun)

end

--翻牌前
function Desk:stPreflop()
	g.log:deskDebug("stPreflop")
	--下大小盲注
	local bb_act = self.bb_user.s_bet_bb
	if self.bb_user:getChip() < self.bb then
		bb_act = self.bb_user.s_bet_allin
	end
	local sb_act = self.sb_user.s_bet_sb
	if self.sb_user:getChip() < self.sb then
		sb_act = self.sb_user.s_bet_allin
	end
	self:betting(self.bb_user:getSeatId(), self.bb, bb_act)
	self:betting(self.sb_user:getSeatId(), self.sb, sb_act)
	--如果是新入玩家可能要加前注
	if self.old_player_num > 1 then
		local users = g.user_mgr:getPlayingUser()
		for _, user in pairs(users) do
			if user:getRound() == 1 then
				local bb_act = user.s_bet_pre
				if user:getChip() < self.bb then
					bb_act = user.s_bet_allin
				end
				local pre_bet = self.bb - user:getSeatBet()
				if pre_bet > 0 then
					self:betting(user:getSeatId(), pre_bet, bb_act)
				end
			end
		end
	end

	local users = g.user_mgr:getPlayingUser()
	--每个玩家发2个牌
	for uid, user in pairs(users) do
		local cards = g.rule:getNextCards(2, uid)
		user:setCards(cards)
		local rank = g.rule:evaluate(cards, {}) --牌型
		user:setHandRank(rank)
	end
	self:pushPreflop()
	self:playerOper(self.s_stage_preflop)


	for _, user in pairs(users) do
		local rank = g.rule:evaluate(user:getCards(), self.final_cards) --牌型
		user:setFinalRank(rank) --最终的牌值
	end
end

function Desk:stFlop()
	g.log:deskDebug(0, "stFlop")
	--入局了
	local users = g.user_mgr:getPlayingUser()
	for _, user in pairs(users) do
		user:setVPIP(1)
		user:setPFR(1)
		if user:getSeatBet() > self.bb + self.pre_bet then
			user:setPFR(2)
		end
	end
	--发3张公牌
	self.common_cards = {}
	local cards = self.final_cards
	if self.use_skill then
		local good_cards = g.rule:setGoodCards(self.need_uid)
		if good_cards then
			cards = good_cards
			--g.log:err("1111111cards:", cards)
		end
	end
	for i=1, 3 do
		table_insert(self.common_cards, cards[i])
	end
	self:pushPot()
	self:showCards()
	self:pushFlop(self.common_cards)
	self:playerOper(self.s_stage_flop)

end

function Desk:stTurn()
	g.log:deskDebug(0, "stTurn")
	--发1张公牌
	local card = self.final_cards[4]
	if self.use_skill then
		local good_cards = g.rule:setGoodCards(self.need_uid)
		if good_cards and next(good_cards) then
			card = good_cards[1]
			--g.log:err("22222222cards:", card)
		end
	end
	table_insert(self.common_cards, card)
	local cards = {card}
	self:pushPot()
	self:showCards()
	self:pushTurn(cards)
	self:playerOper(self.s_stage_turn)
end

function Desk:stRiver()
	g.log:deskDebug(0, "stRiver")
	--发1张公牌
	local card = self.final_cards[5]
	if self.use_skill then
		local good_cards = g.rule:setGoodCards(self.need_uid)
		if good_cards and next(good_cards) then
			card = good_cards[1]
		end
	end
	table_insert(self.common_cards, card)
	local cards = {card}
	self:pushPot()
	self:showCards()
	self:pushRiver(cards)
	self:playerOper(self.s_stage_river)
end

--结束游戏
function Desk:stOver()
	self.is_calc_over = false --是结算完毕
	self:pushPot()
	--游戏结束做结算统计
	local users = self:getPlayers()
	local seat_win = {} --{seat_id = xx} 赢家位置
	local pot_seats_win = {} --池中那个玩家位赢
	local has_pots = false
	local win_pot_num = 0 --有人赢的池数
	if self.pots[1] == 0 then
		--没有分池
		local win_rank = nil --赢的牌型
		local win_seat_ids = {} --赢的位置
		for _, user in pairs(users) do
			if user:isGaming() then
				if not win_rank or user:getRank() < win_rank then --rank越小，牌型越大
					win_rank = user:getRank()
				end
			end
		end
		local win_users = {}
		for _, user in pairs(users) do
			local sid = user:getSeatId()
			if user:isGaming() then
				if not win_rank or user:getRank() == win_rank then
					table_insert(win_seat_ids, sid)
					table_insert(win_users, user)
				end
			end
			if user:getSeatBet() > 0 then
				self.pot_seats[1][sid] = true
			end
		end
		local win_num = #win_seat_ids
		local win_avg_pot = math_floor(self.total_bet/ win_num) --池的平均数
		--print("win_seat_ids-->", tostring(win_seat_ids),  self.total_bet, win_num, win_avg_pot)
		--如果小盲>=100， win_avg_pot 有小数时应该把 self.total_bet减去平分部分后剩下的送给下注多的就可以了
		if win_num > 1 and self.sb >= 100 and win_avg_pot % 100 ~= 0 then
			win_avg_pot = math_floor(self.total_bet/ win_num / 100) * 100
			local less = self.total_bet - win_avg_pot * win_num
			table.sort(win_users, function(a, b)
				return  a:getSeatBet() > b:getSeatBet()
			end)
			for i=less, 100, -100 do
				local user = table.remove(win_users, 1)
				if not user then break end
				local sid = user:getSeatId()
				seat_win[sid] = (seat_win[sid] or 0) + 100
			end
		end
		for _, sid in pairs(win_seat_ids) do
			seat_win[sid] = (seat_win[sid] or 0) + win_avg_pot
			if not pot_seats_win[1] then pot_seats_win[1] = {} end
			pot_seats_win[1][sid] = win_rank
		end
	else
		--有分池产生
		has_pots = true
		local pot_rank = 0 --池中最大牌rank
		--比较每个池的牌值大小得到赢家
		for k, v in pairs(self.pot_seats) do
			local win_seat_ids = {} --赢的位置
			local win_rank = nil --赢的牌型
			local win_num = 0 --赢的人数
			local win_avg_pot = 0 --池是的平分数
			if not next(v) then
				break
			end
			--print("#######1#####pot_seats#####", tostring(v))
			for sid, b in pairs(v) do
				local user = g.user_mgr:getSeatUser(sid)
				if b and user and user:isGaming() then
					if not win_rank or user:getRank() < win_rank then
						--一个池中最大的牌型
						win_rank = user:getRank()
					end
				end
			end
			g.log:deskInfo(0, string.format("pot:%s win_rank:%s", k, win_rank))
			local win_users = {}
			if win_rank then
				for sid, b in pairs(v) do
					local user = g.user_mgr:getSeatUser(sid)
					if b and user and user:isGaming() then
						if user:getRank() == win_rank then
							table_insert(win_seat_ids, sid)
							table_insert(win_users, user)
							user:addWinPot(k)
						end
					end
				end
			end
			--print("#######3#####pot_seats#####", tostring(win_seat_ids))
			win_num = #win_seat_ids
			if win_num <= 0 then
				g.log:deskErr(0, string.format("croom.calcWin winSeatids null rid=%s  hpot.seats=%s", self.desk_id, k, tostring(v), self.pot_seats))
				return
			end
			win_avg_pot = math_floor(self.pots[k]/ win_num) --池的平均数
			--如果小盲>=100， win_avg_pot 有小数时应该把 self.total_bet减去平分部分后剩下的送给下注多的就可以了
			if win_num > 1 and self.sb >= 100 and win_avg_pot % 100 ~= 0  then
				win_avg_pot = math_floor(self.total_bet/ win_num / 100) * 100
				local less = self.total_bet - win_avg_pot * win_num
				table.sort(win_users, function(a, b)
					return  a:getSeatBet() > b:getSeatBet()
				end)
				for i=less, 100, -100 do
					local user = table_remove(win_users, 1)
					if not user then break end
					local sid = user:getSeatId()
					seat_win[sid] = (seat_win[sid] or 0) + 100
				end
			end
			for _, sid in pairs(win_seat_ids) do
				seat_win[sid] = (seat_win[sid] or 0) + win_avg_pot
				if not pot_seats_win[k] then pot_seats_win[k] = {} end
				pot_seats_win[k][sid] = win_rank
			end
			if table.size(v) > 1 then --池中人数>1, 每个池中rank不相等
				if pot_rank ~= win_rank then
					win_pot_num = win_pot_num + 1
					pot_rank = win_rank
				end
			end
		end
	end
	local player_num = g.user_mgr:getPlayingUserNum()
	local users = g.user_mgr:getPlayingUser()
	for _, user in pairs(users) do
		user:setWTSD(1)
		local sid = user:getSeatId()
		if seat_win[sid] then --亮牌后赢了
			user:setWSD(1)
		end
	end
	g.log:deskDebug(0, string.format("gameover seat_win:%s common_cards:%s", tostring(seat_win), tostring(self.common_cards)))
	g.log:deskDebug(0, "gameover pot_seats_win", pot_seats_win)
	self:addChip(seat_win)
	--发送输赢结果
	self:pushGameover(pot_seats_win)
	--最好牌
	self:sendBestCards()
	--亮牌
	self:pushShowcards2()
	--jackpot
	self:checkJackpot(pot_seats_win)
	--输赢日志
	self:sendTableLogs()
	self:addRobotChipPool()
	--有人赢的池数多时间要跟着变
	--都弃牌只需要2.4S时长
	local delay_time = self.stateTime.over
	if win_pot_num > 1 then
		delay_time = delay_time + math_floor(4 * (win_pot_num-1))
	end
	if player_num == 1 then
		delay_time = 4
	end
	local callback = function ()
		self:changeStage(self.s_stage_rest)
	end
	self.oper_timer_id = self.oper_timer:timeout(delay_time, callback)

	self.is_calc_over = true --是结算完毕
end

--休息
function Desk:stReset()
	g.log:deskDebug(0, "stReset")

	--重置数据
	self:reset()
	self:checkUser()
	local user_num = 0
	local check_robot_time = 0
	--有2个以上的玩家才可以开始玩
	g.fork(function()
		::CHECK_STAR::
		while true do
			user_num = g.user_mgr:getSeatUsersNum()
			self:checkUser()
			if self.closed then
				return true
			end
			if user_num >= self.start_play_limit then
				g.log:debug(0, "1stReset->", user_num, self.start_play_limi)
				local player_num = g.user_mgr:getPlayerNum()
				local robot_num = g.user_mgr:getRobotNum()
				if player_num >= 1 and robot_num == 1 and user_num < 6 then
					--尽量避免机器人太少了
					g.sendGames("bot_chek_desk", {rid=g.rid, tid=g.tid})
				end
				break
			end

			check_robot_time = check_robot_time + 1
			if check_robot_time > 3 then
				check_robot_time = 0
				local player_num = g.user_mgr:getPlayerNum()
				if player_num == 1 or user_num == 1 then
					g.sendGames("bot_chek_desk", {rid=g.rid, tid=g.tid})
				end
			end

			g.sleep(100)
		end
		local user_num = g.user_mgr:getSeatUsersNum()
		if user_num >= self.start_play_limit then
			g.log:deskDebug(0, "2stReset->", user_num, self.start_play_limi)
			self:changeStage(self.s_stage_start)
			return true
		else
			goto CHECK_STAR
		end
	end)

end

--检查用户状态
function Desk:checkUser()
	--如果玩家已离线，踢出
	local users = g.user_mgr:getUsers()
	if self.closed then
		for uid, user in pairs(users) do
			local sid = user:getSeatId()
			if user:isSeating() then
				g.user_mgr:standUp(uid)
				self:sendUsers("TS_2C_standupBc", {
					mid = uid,
					tid = g.desk_id,
					seatid = sid,
				})
			end
			self:backChip(user)
			self:sendUsers("TS_2C_leaveBc", {
				mid = uid,
				tid = g.desk_id,
				seatid = sid,
			})
		end
		g.user_mgr:removeUsers()
		return
	end
	local need_removes = {}
	local rand_num = math.random(1, 100)
	local cur_time = g.time()
	local users = g.user_mgr:getSeatUsers()
	for sid, user in pairs(users) do
		local uid = user:getUid()
		local no_oper_num = user:getNoOperNum()
		if no_oper_num > 0 then
			user:addNoOperRound()
		end
		local no_oper_round = user:getNoOperRound()
		--如果玩家已经不够币, 站起
		--无操作2数, 站起
		if user:getChip() <= 0 or no_oper_round > g.const.room.no_oper_round then
			g.log:deskDebug(uid, "checkUser no_oper_round:",user:getChip(), no_oper_round, g.const.room.no_oper_round)
			g.user_mgr:standUp(uid)
			self:sendUsers("TS_2C_standupBc", {
				mid = uid,
				tid = g.desk_id,
				seatid = sid,
			})
			self:backChip(user)
			if user:getDisconnect() or user:isRobot() then
				--从user_manager中删除
				g.user_mgr:removeUser(uid)
				self:sendUsers("TS_2C_leaveBc", {
					mid = uid,
					tid = g.desk_id,
					seatid = sid,
				})
				--return true
			end
		end
		--g.log:debug("check_user:", uid, cur_time - user:getStartTime(), cur_time - user:getResetStatusTime(), rand_num)
		if user:isRobot() and not next(need_removes) then
			if rand_num > 60 then
				if  cur_time - user:getResetStatusTime() > 15 then
					--在reset状态的等待时间太久了
					table_insert(need_removes, uid)
				end
				if cur_time - user:getStartTime() > math.random(180, 500) then
					--玩的时间太久了
					table_insert(need_removes, uid)
				end
			end
		end
	end
	--旁观时间太久自动踢出
	local users = g.user_mgr:getUsers()
	for _, user in pairs(users) do
		if not user:isSeating() then
			local uid = user:getUid()
			--玩家挂机太久也踢出桌子
			--g.log:debug("check_user:", uid, cur_time - user:getStartTime(), cur_time - user:getResetStatusTime())
			local max_look_time = g.const.max_look_time or 120
			if cur_time - user:getResetStatusTime() > max_look_time then
				table_insert(need_removes, uid)
			end
		end
	end
	if #need_removes > 0 then
		g.log:deskDebug("check_user: need_removes", need_removes)
	end
	for k, uid in pairs(need_removes) do
		--机器人呆的时间长了有一定概率离开
		local user = g.user_mgr:getUser(uid)
		if user then
			local sid = user:getSeatId()
			if sid > 0 then
				g.user_mgr:standUp(uid)
				self:sendUsers("TS_2C_standupBc", {
					mid = uid,
					tid = g.tid,
					seatid = sid,
				})
			end
			self:backChip(user)
			self:sendUsers("TS_2C_leaveBc", {
				mid = uid,
				tid = g.tid,
				seatid = sid,
			})
			g.user_mgr:removeUser(uid)

		end
	end

	--删除所有机器人
	if self.remove_robots then
		self.remove_robots = false
		self:removeRobots()
	end

end


----------------------------------
-- 数据操作
----------------------------------

--玩家下注
function Desk:onBet(uid, msg)
	g.log:deskInfo(uid, "onBet ", tostring(msg))
	local user = g.user_mgr:getUser(uid)
	if not user or not user:isGaming() then return end
	local seat_id = user:getSeatId()
	local chips = math_floor(msg.chips)
	--不在指定状态的下注无效
	if self:getStage() ~= self.s_stage_preflop and self:getStage() ~= self.s_stage_flop and self:getStage() ~= self.s_stage_turn and
			self:getStage() ~= self.s_stage_river then
		g.log:deskDebug(uid, "onBet err ", self:getStage(), tostring(msg))
		return
	end
	if not self.cur_oper_seat_id or seat_id ~= self.cur_oper_seat_id then
		g.log:deskWarn(uid, string.format("onBet seat_id:%s, cur_oper_seat_id:%s", seat_id, self.cur_oper_seat_id))
		return {
			code = g.error_code.fail,
			tid = g.desk_id,
		}
	end
	local bet = self:betting(seat_id, chips)
	if not bet then
		g.log:deskWarn(uid,"onBet can_bet false ")
		return {
			code = g.error_code.fail,
			tid = g.desk_id,
		}
	end
	user:checkComeback() --离开状态检查
	if self:getStage() == self.s_stage_preflop then
		if chips == -1 then
			user:addGiveupNum()
		else
			user:setGiveupNum(0)
		end
	end
	--停止定时器
	self.oper_timer:deltimer(self.oper_timer_id)
	self:setRank(user)
	self:playerOper() --继续下一个玩家操作

	return {code = g.error_code.ok, bet = bet, tid = g.tid, total_bet = user:getStageBet()}
end

--状态数字
function Desk:getStageNum()
	local stage = self:getStage()
	return self.state_num[stage] or 0
end

--计算牌值
function Desk:setRank(user)
	if not user:isGaming() and not user:isGiveup() then
		--没有在游戏中
		return
	end
	local hand_cards = user:getCards()
	local common_cards = self.common_cards
	if not next(hand_cards) and not next(common_cards) then
		g.log:deskErr(0, "setRank:",user:getUid(), hand_cards, common_cards)
		return
	end
	if not next(common_cards) then
		user:setKind(1)
		--只有2张牌可以计算对子
		local card1 = hand_cards[1] & 0x0F
		local card2 = hand_cards[2] & 0x0F
		if card1 == card2 then
			user:setKind(2)
		end
		return
	end
	--玩家牌型
	local rank = g.rule:evaluate(hand_cards, common_cards) --牌型
	local kind = g.rule:getKind(rank)
	user:setRank(rank)
	user:setKind(kind)
	local best_cards = g.rule:getBestCards(kind, hand_cards, common_cards)
	user:setBestCards(best_cards)

end

-------------------------------------------------------------------------------
-- 推送消息
-------------------------------------------------------------------------------

function Desk:pushStart()
	local tb = {
		mids={},
		chips={},
	}
	local users = self:getPlayers() --入局了的玩家
	for _, user in pairs(users) do
		table_insert(tb.mids, user:getUid())
		table_insert(tb.chips, user:getChip())
	end
	local data = {
		tid = g.desk_id,
		msg = cjson.encode(tb),
		lid = self.lid,
		sb = self.sb,
		bb = self.bb,
		up_blind_time = self.up_blind_time or 0,
	}
	self:sendUsers("TS_2C_gamebeginBc", data)
	--本局庄家
	self:pushButton()
	g.log:deskDebug("pushStart:", data)
end

--本局庄家
function Desk:pushButton()
	local data = {
		tid = g.desk_id,
		seatid = self.banker_seat_id,
		sb = self.sb_user:getSeatId(),
		bb = self.bb_user:getSeatId(),
	}
	self:sendUsers("TS_2C_buttonBc", data)
end

--翻牌前
function Desk:pushPreflop()
	local users = g.user_mgr:getUsers()
	for _, user in pairs(users) do
		if user:isSeating() and (user:isGaming() or user:isGiveup()) then
			self:setRank(user)
			local cards = user:getClientCards()
			local data = {
				tid = g.desk_id,
				card = cards,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_preflop", data)
		else
			self:sendUser(user, "TS_2C_preflop", { tid=g.desk_id, card={}, kind=1 })
		end
	end
end

--翻牌
function Desk:pushFlop(cards)
	local users = g.user_mgr:getUsers()
	local card = {}
	for _, v in pairs(cards) do
		table_insert(card, {card=v})
	end
	for _, user in pairs(users) do
		if user:isSeating() and (user:isGaming() or user:isGiveup()) then
			self:setRank(user)
			local data = {
				tid = g.desk_id,
				card = card,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_flopBc", data)
		else
			self:sendUser(user, "TS_2C_flopBc", { tid=g.desk_id, card=card, kind=1 })
		end
	end
end

--转牌
function Desk:pushTurn(cards)
	local users = g.user_mgr:getUsers()
	local card = {}
	for _, v in pairs(cards) do
		table_insert(card, {card=v})
	end
	for _, user in pairs(users) do
		if user:isSeating() and (user:isGaming() or user:isGiveup()) then
			self:setRank(user)
			local data = {
				tid = g.desk_id,
				card = card,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_turnBc", data)
		else
			self:sendUser(user, "TS_2C_turnBc", { tid=g.desk_id, card=card, kind=1 })
		end
	end
end

--河牌
function Desk:pushRiver(cards)
	local users = g.user_mgr:getUsers()
	local card = {}
	for _, v in pairs(cards) do
		table_insert(card, {card=v})
	end
	for _, user in pairs(users) do
		if user:isSeating() and (user:isGaming() or user:isGiveup()) then
			self:setRank(user)
			local data = {
				tid = g.desk_id,
				card = card,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_riverBc", data)
		else
			self:sendUser(user, "TS_2C_riverBc", { tid=g.desk_id, card=card, kind=1 })
		end
	end
end

--下一个下注的用户
function Desk:pushNextOper()
	self.follow_bet = self.stage_bet - self.cur_oper:getStageBet()
	local data = {
		tid = g.desk_id,
		mid = self.cur_oper:getUid(),
		seatid = self.cur_oper:getSeatId(),
		time = self.stateTime.oper,
		min_bet = self.min_raise_bet, --最小加值
		max_bet = self.cur_oper:getChip(),
		follow_bet = self.follow_bet,
		delay = self.oper_timer:getCD(self.oper_timer_id),
	}
	--print("##########pushNextOper####", tostring(data))
	self:sendUsers("TS_2C_nextbetBc", data)
	--机器人操作
	if self.cur_oper:isRobot() then
		g.robo_oper:betChip(self.cur_oper)
	end

end

--广播下注
function Desk:pushBet(bet, user)
	--print("#######pushBet  ", bet)
	--user = user or self.cur_oper
	local uid = user:getUid()
	local data = {
		tid = g.desk_id,
		mid = uid,
		seatid = user:getSeatId(),
		seat_chips = user:getChip(),
		bet = user:getStageBet(), --本轮已下注
		action = user:getAction(),
	}
	self:sendUsers("TS_2C_betBc", data)
end

--奖池
function Desk:pushPot()
	--self:calcPots()
	local pots = {}
	if self.pots[1] == 0 then
		--没有分池的情况
		print("##########pushPot1 ", self.total_bet)
		table_insert(pots, {pot=self.total_bet})
	else
		print("##########pushPot2 ", self.pots[1])
		for k, v in pairs(self.pots) do
			local pot = {pot = v}
			table_insert(pots, pot)
		end
	end
	local data = {
		tid = g.desk_id,
		pots = pots,
	}
	self:sendUsers("TS_2C_potBc", data)
end


--游戏结束
function Desk:pushGameover(pot_seats_win)
	local gusers = {}
	local play_num = g.user_mgr:getPlayingUserNum()
	local users = g.user_mgr:getSeatUsers()
	for sid, v in pairs(users) do
		local cards = {}
		local pot_indexs = {} --池子与玩家数
		if v:isGaming() then
			for i, pots in pairs(self.pot_seats) do
				local count = table.size(pots)
				if pots[sid] and count > 0 and pot_seats_win[i] and pot_seats_win[i][sid] then
					table_insert(pot_indexs, {pos = i, count = count})
				end
			end
			if play_num > 1 then
				cards = v:getClientCards()
				v:setShowCards(v:getCards())
			end
		else
			--弃牌，没有在玩的
		end
		table_insert(gusers, {
			mid = v:getUid(),
			seatid = v:getSeatId(),
			kind = v:getKind(),
			seat_chips = v:getChip(),
			rank = v:getRank(),
			win = v:getWinChip(),
			cards = cards,
			pot_indexs = pot_indexs,
		})
	end
	local data = {
		tid = g.desk_id,
		users = gusers,
	}
	self:sendUsers("TS_2C_gameoverBc", data)
	g.log:deskInfo(0, "gameover: ", g.tid, self.total_bet, tostring(data))

	g.robo_oper:gameOver(gusers)
end

--离线处理
function Desk:disconnectCallback(user)
	local uid = user:getUid()
	local seat_id = user:getSeatId()
	--如果只剩下一个玩家则退出游戏
	local play_num = g.user_mgr:getSeatUsersNum()
	--旁观者掉线马上踢出桌子
	if play_num <= 1 or not user:isSeating() then
		self:backChip(user)
		if user:isSeating() then
			g.user_mgr:standUp(uid)
			self:sendUsers("TS_2C_standupBc", {
				mid = uid,
				tid = g.desk_id,
				seatid = seat_id,
			})
		end
		--从user_manager中删除
		g.user_mgr:removeUser(uid)
		self:sendUser(user, "TS_2C_leaveBc", {
			mid = uid,
			tid = g.desk_id,
			seatid = seat_id,
		})
		return true
	end
	----如果在游戏中
	--if user:isGaming() then
	--	local play_num = g.user_mgr:getPlayingUserNum()
	--	if play_num > 0 and play_num < g.desk.start_play_limit then
	--		if self:getStageNum() < self.state_num[self.s_stage_over] then
	--			self:changeStage(self.s_stage_over)
	--		end
	--	end
	--end

	return true
end

--站起
function Desk:standUpCallback(user)
	--如果在游戏中，弃牌
	local uid = user:getUid()
	local seat_id = user:getSeatId()
	g.user_mgr:standUp(uid)
	--返还到游戏帐户中
	self:backChip(user)
	--通知所有玩家
	self:sendUsers("TS_2C_standupBc", {
		mid = uid,
		seatid = seat_id,
		tid = g.desk_id,
	})
	if user:isGaming() then
		self:betting(seat_id, -1) --弃牌
		user:setStatus(user.s_status_giveup)
		if self.cur_oper_seat_id == seat_id then
			self.oper_timer:deltimer(self.oper_timer_id)
			self:playerOper()
			return
		end
	end
	--如果当前可操作人数为1，直接进入over状态
	local count = g.user_mgr:getPlayingUserNum()
	if count == 1 then
		if self:getStageNum() < self.state_num[self.s_stage_over] then
			self:changeStage(self.s_stage_over)
			return
		end
	end

end

--离桌
function Desk:leaveCallback(user)
	local uid = user:getUid()
	local seat_id = user:getSeatId()

	local play_num = g.user_mgr:getPlayingUserNum()
	if play_num == 1 then
		--只剩下一个人在结算后才能离开
		--if self:getStage() ~= self.s_stage_rest and user:isGaming() then
		--	if user:isPlayer() then
		--		g.log:deskWarn(uid, "leaveCallback", play_num, g.user_mgr:getSeatUsersNum())
		--	end
		--	return {
		--		code = g.error_code.fail,
		--		tid = g.desk_id,
		--	}
		--end
		if user:isGaming() then
			if user:isPlayer() then
				g.log:deskWarn(uid, "leaveCallback", play_num, g.user_mgr:getSeatUsersNum())
			end
			if self.is_calc_over and self:getStageNum() < self.state_num[self.s_stage_over] then
				self.is_calc_over = false
			end
			for i = 1, 5 do
				if self.is_calc_over then
					break
				end
				g.sleep(30) --停1.5秒确保结束数据处理完，不然并发时会出现无用户数据的问题
			end
		end
	end
	--如果在游戏中弃牌
	if user:isGaming() then
		self:betting(seat_id, -1) --如果在游戏中弃牌
		user:setStatus(user.s_status_giveup) --设置弃牌状态
		if self.cur_oper_seat_id == seat_id then
			self.oper_timer:deltimer(self.oper_timer_id)
		end
	end
	--站起
	if user:isSeating() then
		g.user_mgr:standUp(uid)
		self:sendUsers("TS_2C_standupBc", {
			mid = uid,
			tid = g.desk_id,
			seatid = seat_id,
		})
	end
	--返还到游戏帐户中
	self:backChip(user)
	self:sendUsers("TS_2C_leaveBc", {
		mid = uid,
		tid = g.desk_id,
		seatid = seat_id,
	})
	--删除
	g.user_mgr:removeUser(uid)
	--如果在游戏中弃牌
	if user:isGaming() or user:isGiveup() then
		if self.cur_oper_seat_id == seat_id then
			--让牌局继续
			self:playerOper()
			return
		end
	end
	--只剩下一个人直接结束
	local play_num = g.user_mgr:getPlayingUserNum()
	if play_num == 1 then
		if self:getStageNum() < self.state_num[self.s_stage_over] then
			self:changeStage(self.s_stage_over)
		end
	end
end

function Desk:showCards()
	local state = self:getStage()
	if self.state_num[state] <= self.state_num[self.s_stage_preflop] then
		return
	end
	if self.allined then
		return
	end
	local users = g.user_mgr:getPlayingUser()
	local users_num = g.user_mgr:getPlayingUserNum()
	local allin_num = 0
	for _, user in pairs(users) do
		if user:getAction() == user.s_bet_allin then
			allin_num = allin_num + 1
		end
	end
	if users_num - 1 <= allin_num then
		if not self.allined then
			--把所有人的牌亮出来
			self:pushShowcards(users)
			g.sleep(200)
		end
		self.allined = true
	end
end


function Desk:setUserShowCard(sid, cards)
	self.user_show_cards[sid] = cards
	if self:getStage() == self.s_stage_over then
		self:pushShowcards2()
	end
end

--推送jackpot
function Desk:sendJackpot()
	local data = {
		tid = g.tid,
		rid = g.rid,
		jackpot = self.jackpot,
	}
	g.desk:sendUsers("TS_2C_JackpotBc", data)
end

--增加jackpot
function Desk:addJackpot(value)
	if g.user_mgr:getPlayerNum() == 0 then
		--没有玩家
		if math.random(1, 2) == 1 then
			return
		end
	end
	if value <= 0 then return end
	local rid = g.rid
	local ok = g.dp:updateJackpot(rid, value)
	if not ok then
		g.log:deskErr(0, string.format("updateJackpot rid:%s, value:%s", rid, value))
		return false
	end
	local jackpot = g.dp:getJackpot(rid)
	if not jackpot then
		g.log:deskErr(0, string.format("getJackpot rid:%s, value:%s", rid, jackpot))
		return false
	end
	self:setJackpot(jackpot)
	self:sendJackpot()

	--发送jackpot日志
	local data = {
		rid = rid,
		change = value,
		result = jackpot,
		time = g.time(),
		info = "",
		cmd = "logs_jackpot",
	}
	--g.sendLogs("logs_jackpot", data)
	g.dp:setLogsJackpot(data)
	return true
end

function Desk:subJackpot(value, info, award_kind)
	local rid = g.rid
	local ok = g.dp:updateJackpot(rid, value)
	if not ok then
		g.log:deskErr(0, string.format("updateJackpot rid:%s, value:%s", rid, value))
		return false
	end
	local jackpot = g.dp:getJackpot(rid)
	if not jackpot then
		g.log:deskErr(0, string.format("getJackpot rid:%s, value:%s", rid, jackpot))
		return false
	end
	self:setJackpot(jackpot)
	self:sendJackpot()
	--发送jackpot日志
	local data = {
		rid = rid,
		change = value,
		result = jackpot,
		time = g.time(),
		award_kind = award_kind or 0,
		info = info,
		cmd = "logs_jackpot",
	}
	--g.sendLogs("logs_jackpot", data)
	g.dp:setLogsJackpot(data)
	return true
end

--检查jackpot
function Desk:checkJackpot(pot_seats_win)
	local total_fee = self:getFee()
	local rate = (g.room_cfg.jackpot_rate or 100) / 100
	local add_value = total_fee * rate
	g.log:deskDebug(0, "checkJackpot:", g.rid, rate, add_value, total_fee)
	if add_value >= 1 then
		self:addJackpot(add_value)
	end
	local win_seats = pot_seats_win[1] --第一个池赢的玩家位置
	local win_users = {}
	local uids = {}
	local names = {}
	if not win_seats then
		g.log:deskErr(0, "checkJackpot", pot_seats_win)
		return
	end
	for sid, _ in pairs(win_seats) do
		local user = g.user_mgr:getSeatUser(sid)
		if user then
			table_insert(win_users, user)
		end
	end

	--是否中了指定牌型
	local rid = g.rid
	--皇家同花顺 同花顺 4条
	local rates = {[10]=0.5, [9]=0.25, [8]=0.05}
	local award = 0
	local user_kind = 0
	local jackpot = 0
	for _, user in pairs(win_users) do
		user_kind = user:getKind()
		if rates[user_kind] and rates[user_kind] > 0 then
			--增加金币到钱包里
			table_insert(uids, user:getUid())
			table_insert(names, user:getName())
			jackpot = g.dp:getJackpot(rid)
			if not jackpot then
				g.log:err(string.format("getJackpot rid:%s, value:%s", rid, jackpot))
				return false
			end
			award = math.floor(jackpot * rates[user_kind])
			if award < 10 then
				--仓库太低不给中奖
				g.log:deskWarn(0,"jackpot award too small.", jackpot, award, user_kind, uids)
				return
			end
			break
		end
	end
	if award > 0 then
		--中奖了
		g.log:deskInfo(0, string.format("jackpot award:%s, ", award), uids)
		local user_award = math.floor(award / #win_users)
		if user_award == 0 then return end
		local data = {
			mode = g.const.chip.s_m_jackpot,
			remark = g.rid,
			tid = g.tid,
			desc = "from jackpot add",
			sync = true,
			chip = user_award,
			water = 0,
		}
		for _, user in pairs(win_users) do
			--if user:isPlayer() then
				user:updateChip(data)
			--end
		end
		--中奖了
		local info = cjson.encode({mids = uids, names = names})
		self:subJackpot(-award, info, user_kind)
	end
end

function Desk:setJackpot(value)
	self.jackpot = value
end

function Desk:getJackpot()
	return self.jackpot
end



--返回桌子信息
function Desk:getDeskInfo(uid)
	--print("#############getDeskInfo_________", uid)
	local cfg = g.room_cfg
	local user = g.user_mgr:getUser(uid)
	local seats = {}
	local users = g.user_mgr:getSeatUsers()
	local desk = g.desk
	for k, v in pairs(users) do
		local seat = {
			mid = v:getUid(),
			seatid = v:getSeatId(),
			seat_chips = v:getChip(),
			status = v:getStatus(),
			action = v:getAction(),
			bet = v:getStageBet(),
			online = v:getOnline(),
			info = v:getInfo(),
			other = "",
			auto_oper = v:getAutoPlay(),
		}
		table_insert(seats, seat)
	end
	local cards = g.desk:getCommonCards() --公牌
	local pots = g.desk:getPot() --分池
	local self_user = {}
	if user:isSeating() then
		self_user = {
			card = user:getClientCards(),
			kind = user:getKind(),
			min_bet = desk.min_raise_bet, --最小加注值
			max_bet = user:getChip(),
			folow_bet = desk.stage_bet,
		}
	end
	local sb, bb = g.desk:getBind()
	local status = desk:getStageNum()
	local cd_time = desk:getOperCDTime()
	if status > 5 then
		cd_time = 0
	end
	local roomInfo = {
		rid = g.rid,
		tid = g.desk_id,
		sb = sb,
		bb = bb,
		min_buy = math_floor(cfg.min_buy) or 0,
		max_buy = math_floor(cfg.max_buy) or 0,
		button = desk.banker_seat_id,
		cards = cards,
		pots = pots,
		curr_seatid = desk.cur_oper_seat_id or 0,
		cd_time = cd_time, --剩余操作时间
		all_time = desk.stateTime.oper, --总时间
		status = status, --桌子状态
		info = "",
		pre_bet = self.pre_bet or 0, --前注
		up_blind_time = desk.up_blind_time or 0, --涨盲时间
	}
	local res = {
		code = g.error_code.ok,
		seats = seats,
		roominfo = roomInfo,
		selfuser = self_user,
		seatid = user:getSeatId(),
		tid = g.tid,
		rid = g.rid,
		rtype = g.rtype,
	}

	return res
end

--操作时间
function Desk:getOperCDTime()
	local num = self:getStageNum()
	if num >= self.state_num[self.s_stage_preflop] or num <= self.state_num[self.s_stage_river] then
		return math_floor(self.oper_timer:getCD(self.oper_timer_id))
	end
	return 0
end

--有玩家坐下时
function Desk:sitDownCallback(uid)
	--local user = g.user_mgr:getUser(uid)
	--if user:isPlayer() then
	--	g.sendGames("bot_chek_desk", {rid=g.rid, tid=g.tid})
	--end
end

--技术检测
function Desk:checkSkill()
	local max_buy = g.room_cfg.max_buy
	local min_buy = g.room_cfg.min_buy
	self.use_skill = false
	self.need_uid = nil
	if g.user_mgr:getPlayerNum() == 0 then
		return
	end
	local rand_num = math.random(1, 100)
	if self.robot_chip_pool < -min_buy then
		--桌子输太多了，使用必杀技能
		if rand_num < 10 then
			self.use_skill = true
		end
	elseif self.robot_chip_pool < -2*min_buy then
		if rand_num < 30 then
			self.use_skill = true
		end
	elseif self.robot_chip_pool < -3*max_buy then
		if rand_num < 50 then
			self.use_skill = true
		end
	elseif self.robot_chip_pool > max_buy then
		if rand_num < 10 then
			self.use_skill = true
			local users = self:getPlayers()
			local user_size = #users
			if user_size > 0 then
				local user = users[math.random(1, user_size)]
				self.need_uid = user:getUid()
			end
		end
	elseif self.robot_chip_pool > 3*max_buy then
		if rand_num < 20 then
			self.use_skill = true
			local users = self:getPlayers()
			local chip = min_buy
			for k, v in pairs(users) do
				if v:isPlayer() then
					if v:getChip() < chip then
						self.need_uid = v:getUid()
						chip = v:getChip()
					end
				end
			end
		end
	end
	local users = self:getPlayers()
	for k, user in pairs(users) do
		if user:isRobot() then
			local level = math.random(1,10)
			if self.robot_chip_pool < -min_buy then
				level = math.random(5,10)
			elseif self.robot_chip_pool < -2*max_buy then
				level = math.random(7,10)
			end
			if user.setPersonality then
				user:setPersonality(level)
			end
		end
	end
	g.log:deskInfo("checkSkill->",rand_num, self.robot_chip_pool, max_buy,  self.use_skill, self.need_uid)
end

function Desk:getUseSkill()
	return self.use_skill
end

function Desk:getUseSkillUid()
	return self.need_uid
end


function Desk:addRobotChipPool()
	local player_win = 0
	local robot_win = 0
	local users = self:getPlayers()
	for _, v in pairs(users) do
		local win_chip = v:getWinChip()
		if v:isRobot() then
			robot_win = robot_win + win_chip
		else
			player_win = player_win + win_chip
		end
	end
	if player_win ~= 0 and robot_win ~= 0 then
		self.robot_chip_pool = self.robot_chip_pool + robot_win --金币池
	end
end

return Desk